/**************************
* @Summary
* @Author 20009200303 赵传博
* @Date 2022/4/27
*****************************/

#include "Lexer.h"
#include <cmath>
#include <cstring>

/**
 * 使用单例模式后，报错：Undefined refference: Lexer::lexerInstance
 * 因为在.h中的只是declare还没有定义，直接使用lexerInstance是没有定义的
 * 因此要在这里定义
 */
Lexer* Lexer::lexerInstance = nullptr;

Lexer::Lexer(const char *str) {
    this->exprText = (char*)str;
    this->i = 0;
    this->number_value = 0;
}

Token_type Lexer::get_token() {
    char ch = 0;

    /* 如果就这么一句，难以将;和\n都看做输入结束 */
    //cin >> ch;

    do{
        ch = exprText[i++];
        if(!ch) return curr_tok = END;
    }while(ch != '\n' && isspace(ch));

    switch (ch) {
        /* 如果是已经定义好的Token_type，直接返回其类型即可 */
        case '*': case '/': case '+': case '-':
        case '(': case ')': case '=':
            return curr_tok = Token_type(ch);

        /* 如果是一行表达式的末尾 */
        case ';': case '\n':
            return curr_tok = PRINT;

        /* 如果是一个数字(或者小数点) */
        case '0': case '1': case '2': case '3': case '4': case '5':
        case '6': case '7': case '8': case '9': case '.':{
            int isInt = 1;
            do {
                if(ch == '.'){
                    isInt = -1;
                    continue;
                }
                if(isInt >= 0){
                    number_value = number_value * 10 + ch - '0';
                }else{
                    number_value = number_value + (double)(ch - '0') / pow(10, -isInt);
                    --isInt;
                }
            }while(isdigit(ch = exprText[i++]) || ch == '.');
            --i;
            return curr_tok = NUMBER;
        }
        /* 如果是一个变量：NAME，或者发生错误 */
        default:
            if(isalpha(ch)){
//                cin.putback(ch);
//                cin >> string_value;
//                return curr_tok = NAME;
            /**
             * 采用>>读入字符串直到空白会引起问题，这一问题可以通过一次读一个字符，直到遇到
             * 非字母非数字字符的方式解决
             */
                string_value = ch;
                while((ch = exprText[i++]) && isalnum(ch)){
                    string_value.push_back(ch);
                }
                --i;
                return curr_tok = NAME;
            }//xabc=13

            cerr << "bad token" << endl;
            return curr_tok = PRINT;
    }
}

map<string, double> &Lexer::getTable() {
    return table;
}

void Lexer::setNumberValue(double numberValue) {
    number_value = numberValue;
}


Lexer *Lexer::getInstance(const char* str) {
    if(!lexerInstance){
        lexerInstance = new Lexer(str);
    }
    return lexerInstance;
}

void Lexer::clear() {
    strcpy(exprText, "\0");
    i = 0;
    number_value = 0;
    string_value.clear();
}



